package com.gitee.alpha.ie;

import com.gitee.alpha.ie.RowReadStatus.Status;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.excel.context.AnalysisContext;
import com.gitee.alpha.framework.mvc.AbstractController;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import java.util.List;
import java.util.Map;

/**
 * 简单实现Excel读取数据收集器(使用Controller继承{@link ReadCallback})<br>
 *
 * @author 冰羽
 * @version 2.2.0
 */
public abstract class AbstractReadCallback<T> extends AbstractController<T>
    implements ReadCallback {

  private final Map<Class<?>, List<RowWrapper>> _TEMP_DATA_ = Maps.newHashMap();

  @Override
  public void callback(
      Exception e, List<RowWrapper> list, ReadContext readContext, AnalysisContext context) {
    Status status = readContext.readStatus();

    if (e == null) {
      // 当没有异常的时候暂存数据
      // 以 entityClass分类存储
      set(list);
    }

    this.importHandler(e, list, readContext, context);
  }

  /**
   * 业务处理, 需要重写
   *
   * @param e 读取数据过程中出现的异常
   * @param list 临时数据/和{@link ExcelReadAnalysisListener}中的batchSize有关
   * @param readContext 读取数据的上下文对象
   * @param context {@link AnalysisContext}
   */
  protected void importHandler(
      Exception e, List<RowWrapper> list, ReadContext readContext, AnalysisContext context) {
    this.clear();
  }

  /** 清空临时数据容器 */
  protected void clear() {
    this._TEMP_DATA_.clear();
  }

  private void set(List<RowWrapper> list) {
    if (CollectionUtil.isNotEmpty(list)) {
      list.forEach(wrapper -> set(wrapper));
    }
  }

  private void set(RowWrapper wrapper) {
    // Null pointer?/
    try {
      Class<?> clazz = wrapper.getEntityType();
      List<RowWrapper> list = this.get(clazz);
      if (CollectionUtil.isEmpty(list)) {
        list = Lists.newArrayList();
      }

      list.add(wrapper);
      set(clazz, list);
    } catch (Exception e) {

    }
  }

  private void set(Class<?> clazz, List<RowWrapper> list) {
    this._TEMP_DATA_.put(clazz, list);
  }

  protected List<RowWrapper> get(Class<?> clazz) {
    return this._TEMP_DATA_.get(clazz);
  }
}
